#! /usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'Chuck Li'

import ctypes
import pyaudio
import wave
import os
import time
import sys

c_int = ctypes.c_int
byref = ctypes.byref
c_voidp = ctypes.c_void_p
c_char_p = ctypes.c_char_p
string_at = ctypes.string_at

lib_path = os.path.dirname(os.path.realpath(__file__)) + '/../libs/libmsc.so'
msc = ctypes.cdll.LoadLibrary(lib_path)

login_params = b"appid = 56ee43d0, work_dir = ."
tts_sb_params = b"voice_name = xiaoyan, text_encoding = UTF8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"
stt_sb_params = b"sub = iat, ptt = 0, result_encoding = utf8, result_type = plain, domain = iat"
wav_header = b"RIFF6n\x06\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00\x80>\x00\x00\x00}\x00\x00\x02\x00\x10\x00data\x00\x00\x00\x00"

MSP_SUCCESS = 0
MSP_TTS_FLAG_STILL_HAVE_DATA = 1
MSP_TTS_FLAG_DATA_END = 2
MSP_TTS_FLAG_CMD_CANCELED = 4

MSP_AUDIO_SAMPLE_FIRST = 1
MSP_AUDIO_SAMPLE_CONTINUE = 2
MSP_AUDIO_SAMPLE_LAST = 4
MSP_REC_STATUS_COMPLETE = 5

FRAME_LEN = 640  # Byte

filename = "MSP.wav"
chunk = 1024


class MSP:

    def __init__(self):
        self.logined = False
        print(('logined =>'), self.logined)

    def login(self):
        if self.logined == True:
            return 0

        ret = msc.MSPLogin(None, None, login_params)
        print(('MSPLogin =>'), ret)
        if ret == 0:
            self.logined = True
        return ret

    def logout(self):
        ret = msc.MSPLogout()
        print('MSPLogout =>', ret)
        if ret == 0:
            self.logined = False
        return ret

    def tts(self, text, filename=filename, params=tts_sb_params):
        if self.logined == False:
            if self.login() != 0:
                return -1

        ret, audio_len, synth_status, getret, wav_datasize = c_int(), c_int(), c_int(), c_int(), c_int()
        session_id = msc.QTTSSessionBegin(params, byref(ret))
        ret = msc.QTTSTextPut(session_id, text, len(text), None)

        wave_file = open(filename, 'wb')
        wave_file.write(wav_header)

        p = pyaudio.PyAudio()
        stream = p.open(format=8, channels=1, rate=16000, output=True)

        while True:
            data = msc.QTTSAudioGet(session_id, byref(audio_len), byref(synth_status), byref(getret))
            # if audio_len.value > 0:
                # print('datasize: %d\r' % wav_datasize.value, end='\r')
            if getret.value != MSP_SUCCESS:
                break
            if data:
                stream.write(string_at(data, audio_len))
                wave_file.write(string_at(data, audio_len))
                wav_datasize.value += audio_len.value
            if synth_status.value == MSP_TTS_FLAG_DATA_END:
                break

        # print('')
        time.sleep(0.3)
        stream.stop_stream()
        stream.close()
        p.terminate()

        if wav_datasize.value > 0:
            wav_size8 = c_int()
            wav_size8.value = 44 + wav_datasize.value - 8
            wave_file.seek(4)
            wave_file.write(wav_size8)
            wave_file.seek(40)
            wave_file.write(wav_datasize)

        wave_file.close()
        msc.QTTSSessionEnd(session_id, "Normal")

    def isr(self, pcm, params=stt_sb_params):
        if self.logined == False:
            if self.login() != 0:
                return -1
        laststr = ''
        ret = c_int()
        sessionID = c_voidp()
        msc.QISRSessionBegin.restype = c_char_p
        sessionID = msc.QISRSessionBegin(None, params, byref(ret))

        piceLne = FRAME_LEN * 20
        epStatus = c_int(0)
        recogStatus = c_int(0)

        len_pcm = len(pcm)
        if len_pcm == 0:
            return laststr

        f_start = 0
        if len_pcm < piceLne:
            f_end = len_pcm
        else:
            f_end = piceLne

        frames = pcm[f_start:f_end]

        ret = msc.QISRAudioWrite(sessionID, frames, len(frames), MSP_AUDIO_SAMPLE_FIRST,
                                 byref(epStatus), byref(recogStatus))

        while True:
            f_start = f_end
            f_end += piceLne
            if f_end > len_pcm:
                f_end = len_pcm

            frames = pcm[f_start:f_end]
            ret = msc.QISRAudioWrite(sessionID, frames, len(frames), MSP_AUDIO_SAMPLE_CONTINUE,
                                     byref(epStatus), byref(recogStatus))
            if f_end == len_pcm:
                break

        ret = msc.QISRAudioWrite(sessionID, None, 0, MSP_AUDIO_SAMPLE_LAST, byref(epStatus), byref(recogStatus))

        counter = 0
        while recogStatus.value != MSP_REC_STATUS_COMPLETE:
            ret = c_int()
            msc.QISRGetResult.restype = c_char_p
            retstr = msc.QISRGetResult(sessionID, byref(recogStatus), 0, byref(ret))
            if retstr is not None:
                laststr += retstr.decode()

            counter += 1
            time.sleep(0.1)
            counter += 1
            if counter == 500:
                laststr += '[识别失败]'
                break

        ret = msc.QISRSessionEnd(sessionID, '\0')
        return laststr

    def play_pcm(self, pcm):
        p = pyaudio.PyAudio()
        stream = p.open(format=8, channels=1, rate=16000, output=True)
        stream.write(string_at(pcm, len(pcm)))
        time.sleep(0.3)
        stream.stop_stream()
        stream.close()
        p.terminate()


msp = MSP()
